﻿#region Copyright
// Copyright (c) 2011-2012 RaisingForce Team (Alikin Sergey)
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#endregion

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using RaisingForce.Raise.Measures;

namespace RaisingForce.Raise.Presentation.ViewModel.Specialized
{
    public class SelectMeasuresViewModel :
        ViewModelBase
    {
        #region Constructors

        public SelectMeasuresViewModel(ISettingMeasures usingMeasures)
            : base()
        {
            if (usingMeasures == null)
            {
                throw new ArgumentNullException("usingMeasures");
            }
            Contract.EndContractBlock();
            this.selectedMeasures = new SettingMeasures(usingMeasures);
            // setup Distance measure selector            
            this.DistanceMeasures = new ObservableCollection<DoubleMeasureViewModel<IDistanceMeasure>>(
                MeasureHelper.SupportedDistanceMeasures.ToViewModels());
            this.SelectedDistanceMeasure = this.selectedMeasures.DistanceMeasure.ToViewModel();
            this.distanceMeasureSelector.PropertyChanged +=
                this.distanceMeasureSelector_PropertyChanged;
            this.distanceMeasureSelector.SelectionChanged +=
                this.distanceMeasureSelector_SelectionChanged;
            // setup Time measure selector
            this.TimeMeasures = new ObservableCollection<DoubleMeasureViewModel<ITimeMeasure>>(
                MeasureHelper.SupportedTimeMeasures.ToViewModels());
            this.SelectedTimeMeasure = this.selectedMeasures.TimeMeasure.ToViewModel();
            this.timeMeasureSelector.PropertyChanged +=
                this.timeMeasureSelector_PropertyChanged;
            this.timeMeasureSelector.SelectionChanged +=
                this.timeMeasureSelector_SelectionChanged;
            // setup Angle measure selector
            this.AngleMeasures = new ObservableCollection<DoubleMeasureViewModel<IAngleMeasure>>(
                MeasureHelper.SupportedAngleMeasures.ToViewModels());
            this.SelectedAngleMeasure = this.selectedMeasures.AngleMeasure.ToViewModel();
            this.angleMeasureSelector.PropertyChanged +=
                this.angleMeasureSelector_PropertyChanged;
            this.angleMeasureSelector.SelectionChanged +=
                this.angleMeasureSelector_SelectionChanged;
        }

        #endregion

        #region Private Members

        private readonly ItemSelectorViewModel<DoubleMeasureViewModel<IDistanceMeasure>> distanceMeasureSelector =
            new ItemSelectorViewModel<DoubleMeasureViewModel<IDistanceMeasure>>();

        private readonly ItemSelectorViewModel<DoubleMeasureViewModel<ITimeMeasure>> timeMeasureSelector =
            new ItemSelectorViewModel<DoubleMeasureViewModel<ITimeMeasure>>();

        private readonly ItemSelectorViewModel<DoubleMeasureViewModel<IAngleMeasure>> angleMeasureSelector =
            new ItemSelectorViewModel<DoubleMeasureViewModel<IAngleMeasure>>();

        private readonly SettingMeasures selectedMeasures;

        #endregion

        #region Private SelectionChanged Event Handlers

        private void distanceMeasureSelector_SelectionChanged(object sender, EventArgs e)
        {
            IDistanceMeasure selectedDistanceMeasure =
                this.SelectedDistanceMeasure.Measure;
            this.selectedMeasures.DistanceMeasure = selectedDistanceMeasure;
            this.OnMeasureSelectionChanged();
        }

        private void timeMeasureSelector_SelectionChanged(object sender, EventArgs e)
        {
            ITimeMeasure selectedTimeMeasure =
                this.SelectedTimeMeasure.Measure;
            this.selectedMeasures.TimeMeasure = selectedTimeMeasure;
            this.OnMeasureSelectionChanged();
        }

        private void angleMeasureSelector_SelectionChanged(object sender, EventArgs e)
        {
            IAngleMeasure selectedAngleMeasure =
                this.SelectedAngleMeasure.Measure;
            this.selectedMeasures.AngleMeasure = selectedAngleMeasure;
            this.selectedMeasures.AngleTextFormat =
                MeasureHelper.GetAngleTextFormat(selectedAngleMeasure);
            this.selectedMeasures.AngleMeasureFormatString =
                MeasureHelper.GetAngleMeasureFormatString(selectedAngleMeasure);
            this.OnMeasureSelectionChanged();
        }

        #endregion

        #region Private PropertyChanged Event Handlers

        private void onSelectorPropertyChanged(
            string propertyName,
            string selectedItemPropertyName,
            string itemsPropertyName,
            string isEnabledPropertyName)
        {
            Contract.Requires(selectedItemPropertyName != null);
            Contract.Requires(itemsPropertyName != null);
            string resultingPropertyName;
            switch (propertyName)
            {
                case propItemSelector_SelectedItem:
                    resultingPropertyName = selectedItemPropertyName;
                    break;
                case propItemSelector_Items:
                    resultingPropertyName = itemsPropertyName;
                    break;
                case propItemSelector_IsReadOnly:
                    resultingPropertyName = propIsEnabled;
                    break;
                default:
                    resultingPropertyName = null;
                    break;
            }
            if (resultingPropertyName != null)
            {
                this.OnPropertyChanged(resultingPropertyName);
            }
        }

        private void distanceMeasureSelector_PropertyChanged(
            object sender,
            PropertyChangedEventArgs e)
        {
            this.onSelectorPropertyChanged(
                e.PropertyName,
                propSelectedDistanceMeasure,
                propDistanceMeasures,
                propIsEnabled);
        }

        private void timeMeasureSelector_PropertyChanged(
            object sender,
            PropertyChangedEventArgs e)
        {
            this.onSelectorPropertyChanged(
                e.PropertyName,
                propSelectedTimeMeasure,
                propTimeMeasures,
                propIsEnabled);
        }

        private void angleMeasureSelector_PropertyChanged(
            object sender,
            PropertyChangedEventArgs e)
        {
            this.onSelectorPropertyChanged(
                e.PropertyName,
                propSelectedAngleMeasure,
                propAngleMeasures,
                propIsEnabled);
        }

        #endregion

        #region Private ItemSelectorViewModel Property Constants

        /// <summary>
        /// Property name for ItemSelectorViewModel class.
        /// </summary>
        private const string propItemSelector_SelectedItem = "SelectedItem";

        /// <summary>
        /// Property name for ItemSelectorViewModel class.
        /// </summary>
        private const string propItemSelector_Items = "Items";

        /// <summary>
        /// Property name for ItemSelectorViewModel class.
        /// </summary>
        private const string propItemSelector_IsReadOnly = "IsReadOnly";

        #endregion

        #region Properties

        public ISettingMeasures SelectedMeasures
        {
            get { return this.selectedMeasures; }
        }

        private const string propIsEnabled = "IsEnabled";

        public bool IsEnabled
        {
            get
            {
                return !this.distanceMeasureSelector.IsReadOnly
                    && !this.timeMeasureSelector.IsReadOnly
                    && !this.angleMeasureSelector.IsReadOnly;
            }
            set
            {
                this.distanceMeasureSelector.IsReadOnly = !value;
                this.timeMeasureSelector.IsReadOnly = !value;
                this.angleMeasureSelector.IsReadOnly = !value;
            }
        }

        #endregion

        #region ViewModel Properties

        private int selectorsMinWidth;

        public int SelectorsMinWidth
        {
            get { return this.selectorsMinWidth; }
            set
            {
                this.SetProperty(
                    ref this.selectorsMinWidth,
                    value,
                    "SelectorsMinWidth");
            }
        }

        private string distanceMeasureLabel;

        public string DistanceMeasureLabel
        {
            get { return this.distanceMeasureLabel; }
            set
            {
                this.SetProperty(
                    ref this.distanceMeasureLabel,
                    value,
                    "DistanceMeasureLabel");
            }
        }

        private string timeMeasureLabel;

        public string TimeMeasureLabel
        {
            get { return this.timeMeasureLabel; }
            set
            {
                this.SetProperty(
                    ref this.timeMeasureLabel,
                    value,
                    "TimeMeasureLabel");
            }
        }

        private string angleMeasureLabel;

        public string AngleMeasureLabel
        {
            get { return this.angleMeasureLabel; }
            set
            {
                this.SetProperty(
                    ref this.angleMeasureLabel,
                    value,
                    "AngleMeasureLabel");
            }
        }

        #endregion

        #region MeasureSelectionChanged Event

        public event EventHandler MeasureSelectionChanged;

        protected virtual void OnMeasureSelectionChanged()
        {
            this.OnEvent(this.MeasureSelectionChanged);
        }

        #endregion

        #region DistanceMeasure Selector Properties

        private const string propSelectedDistanceMeasure = "SelectedDistanceMeasure";

        public DoubleMeasureViewModel<IDistanceMeasure> SelectedDistanceMeasure
        {
            get { return this.distanceMeasureSelector.SelectedItem; }
            set { this.distanceMeasureSelector.SelectedItem = value; }
        }

        private const string propDistanceMeasures = "DistanceMeasures";

        public ObservableCollection<DoubleMeasureViewModel<IDistanceMeasure>> DistanceMeasures
        {
            get { return this.distanceMeasureSelector.Items; }
            private set { this.distanceMeasureSelector.Items = value; }
        }

        #endregion

        #region TimeMeasure Selector Properties

        private const string propSelectedTimeMeasure = "SelectedTimeMeasure";

        public DoubleMeasureViewModel<ITimeMeasure> SelectedTimeMeasure
        {
            get { return this.timeMeasureSelector.SelectedItem; }
            set { this.timeMeasureSelector.SelectedItem = value; }
        }

        private const string propTimeMeasures = "TimeMeasures";

        public ObservableCollection<DoubleMeasureViewModel<ITimeMeasure>> TimeMeasures
        {
            get { return this.timeMeasureSelector.Items; }
            private set { this.timeMeasureSelector.Items = value; }
        }

        #endregion

        #region AngleMeasure Selector Properties

        private const string propSelectedAngleMeasure = "SelectedAngleMeasure";

        public DoubleMeasureViewModel<IAngleMeasure> SelectedAngleMeasure
        {
            get { return this.angleMeasureSelector.SelectedItem; }
            set { this.angleMeasureSelector.SelectedItem = value; }
        }

        private const string propAngleMeasures = "AngleMeasures";

        public ObservableCollection<DoubleMeasureViewModel<IAngleMeasure>> AngleMeasures
        {
            get { return this.angleMeasureSelector.Items; }
            private set { this.angleMeasureSelector.Items = value; }
        }

        #endregion

        #region Public Methods

        public void SetDefaults()
        {
            this.SelectedDistanceMeasure =
                MeasureHelper.DefaultDistanceMeasure.ToViewModel();
            this.SelectedTimeMeasure =
                MeasureHelper.DefaultTimeMeasure.ToViewModel();
            this.SelectedAngleMeasure =
                MeasureHelper.DefaultAngleMeasure.ToViewModel();
        }

        #endregion
    }
}
